package Compile.YUFA;

import Compile.CIFA.Token;
import Compile.CIFA.TokenType;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class yufa {
    // 词法分析得到的Token列表
    private List<Token> tokenList;

    // 当前所指向的输入符号Token
    private int pos;
    private Token SYM;

    // 语法树根节点
    private TreeNode root;
    // 语法树当前节点
    private TreeNode curNode;

    // 记录进行到的语法分析的状态
    private String content;

    // 语法分析是否出错
    private boolean flag = false;

    /*
    * 语法分析构造函数
    * */
    public yufa(List<Token> tokens) {
        this.tokenList = tokens;
        pos = -1;
        content = "";
        root = new TreeNode("E");
        curNode = root;
        PARSER();
    }

    /*
    * 返回语法分析结果
    * */
    public String getContent() {
        return this.content;
    }

    /*
    * 语法分析是否出错
    * */
    public boolean getFlag() {return this.flag;}

    /*
    * 返回语法树（根节点）
    * */
    public TreeNode getRoot() {
        return this.root;
    }

    /*
    * 输出语法树
    * */
    public void displayParserTree() {
        System.out.println("------------------------");
        System.out.println("语法树如下：");
        displayTreeNode(root, 0);
        System.out.println("------------------------");
    }

    /*
    * 输出节点node及其子树
    * level表示其所在层级（从上而下层级由0开始++）
    * */
    private void displayTreeNode(TreeNode node, int level) {
        // 根据层级缩进不同距离
        for (int i = 0; i < level; i++) {
            System.out.print("\t");
        }
        // 展示node节点
        System.out.print("|__");
        System.out.println(node.getValue());
        // 展示孩子节点
        for (TreeNode child : node.getChildren()) {
            displayTreeNode(child, level+1);
        }
    }

    /*
    * 读入下一个Token
    * */
    private void ADVANCE() {
        if (pos < tokenList.size()) {
            pos++;
            SYM = tokenList.get(pos);
        }
    }

    /*
    * 出错处理
    * */
    private void ERROR(String Vn, String Vt) {
        content = "语法分析未通过:\n 在非终结符 " + Vn + " 的语法处出现错误！\n expected: "+ Vt +" \n given: " + SYM.toString();
        flag = true;
    }

    /*
    * 成功
    * */
    private void SUCCESS(String s) {
        content = "语法分析通过: " + s;
    }

    /*
    * 语法分析主方法
    * */
    private void PARSER() {
        // 读入一个输入符号
        ADVANCE();
        // 从文法开始符号开始
        E();
        if (flag) return;
        if (!Objects.equals(SYM.getType(), TokenType.JINGHAO)) {
            ERROR("unexpected input", "#");
        }
    }

    /*
    * 下面采用递归下降分析器，给出每个非终结符对应的处理方法
    * */
    private void E() {
        if (FIRST.E.contains(SYM.getValue())) {
            // S加入语法树（root子节点）
            root.addChild(new TreeNode("S"));
            // 更新当前节点
            curNode = root.getChildren().get(root.getChildren().size()-1);
            S();
        } else ERROR("E", "FIRST.E:" + FIRST.E);
    }

    private void S() {
        if (FIRST.quit_S.contains(SYM.getValue())) {
            quit_S();
        } else if (FIRST.help_S.contains(SYM.getValue())) {
            help_S();
        } else if (FIRST.show_S.contains(SYM.getValue())) {
            show_S();
        } else if (FIRST.create_S.contains(SYM.getValue())) {
            create_S();
        } else if (FIRST.insert_S.contains(SYM.getValue())) {
            insert_S();
        } else if (FIRST.update_S.contains(SYM.getValue())) {
            update_S();
        } else if (FIRST.delete_S.contains(SYM.getValue())) {
            delete_S();
        } else if (FIRST.select_S.contains(SYM.getValue())) {
            select_S();
        } else if (FIRST.desc_S.contains(SYM.getValue())) {
            desc_S();
        } else if (FIRST.drop_S.contains(SYM.getValue())) {
            drop_S();
        } else {
            ERROR("S", "FIRST.S:" + FIRST.S);
        }
    }

    private void quit_S() {
        if (SYM.getValue().equalsIgnoreCase("quit")){
            ADVANCE();
            END();
            if(flag) return;
            SUCCESS("quit");
            // 添加节点
            curNode.addChild(new TreeNode("quit"));
        } else {
            ERROR("quit_S", "quit");
        }
    }

    private void END() {
        if (SYM.getValue().equalsIgnoreCase(";")) {
            ADVANCE();
        } else if (!FOLLOW.END.contains(SYM.getValue())) {
            ERROR("END", "FIRST.E/FOLLOW.E:" + FIRST.E + "/" + FOLLOW.E);
        }
    }

    private void help_S() {
        if (SYM.getValue().equalsIgnoreCase("help")){
            ADVANCE();
            END();
            if(flag) return;
            SUCCESS("help");
            curNode.addChild(new TreeNode("help"));
        } else {
            ERROR("help_S", "help");
        }
    }

    private void show_S() {
//        int start = pos;
        if (SYM.getValue().equalsIgnoreCase("show")){
            ADVANCE();
//            start = pos;
            if (SYM.getValue().equalsIgnoreCase("tables")) {
                ADVANCE();
                END();
                if(flag) return;
                SUCCESS("show tables");
                curNode.addChild(new TreeNode("show"));
            } else {
//                backSYM(start);
                ERROR("show_S", "tables");
            }
        } else {
            ERROR("show_S", "show");
        }
    }

    /*
    * create tablename col_list[colname, type]
    * */
    private void create_S() {
        if (SYM.getValue().equalsIgnoreCase("create")) {
            ADVANCE();
            curNode.addChild(new TreeNode("create"));
            if (SYM.getValue().equalsIgnoreCase("table")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    if (SYM.getValue().equalsIgnoreCase("(")) {
                        ADVANCE();
                        curNode.addChild(new TreeNode("colList"));
                        curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                        COL_DEFINITION_LIST();
                        if(flag) return;
                        if (SYM.getValue().equalsIgnoreCase(")")) {
                            ADVANCE();
                            END();
                            if (flag) return;
                            SUCCESS("create");
                        } else ERROR("create_S", ")");
                    } else ERROR("create_S", "(");
                } else ERROR("create_S",  "TokenType.IDENTIFIER");
            } else ERROR("create_S", "table");
        }
    }

    private void COL_DEFINITION_LIST() {
        if (FIRST.COL_DEFINITION_LIST.contains(SYM.getType().toString())) {
            COL_DEFINITION();
            if(flag) return;
            if (SYM.getValue().equalsIgnoreCase(",")) {
                ADVANCE();
                COL_DEFINITION_LIST();
            }
        } else {
            ERROR("COL_DEFINITION_LIST", "FIRST.COL_DEFINITION_LIST:" + FIRST.COL_DEFINITION_LIST);
        }
    }

    private void COL_DEFINITION() {
        int start = pos;
        if (FIRST.COL_DEFINITION.contains(SYM.getType().toString())) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
            DATA_TYPE();
        } else {
            ERROR("COL_DEFINITION", "FIRST.COL_DEFINITION:" + FIRST.COL_DEFINITION);
        }
    }

    private void DATA_TYPE() {
        int start = pos;
        if (FIRST.DATA_TYPE.contains(SYM.getType().toString())) {
            System.out.println("DATA_TYPE: " + SYM.getType().toString());
            curNode.addChild(new TreeNode(SYM.getType().toString()));
            ADVANCE();
        } else {
            ERROR("DATA_TYPE", "FIRST.DATA_TYPE:" + FIRST.DATA_TYPE);
        }
    }

    private void insert_S() {
        if (SYM.getValue().equalsIgnoreCase("insert")) {
            ADVANCE();
            curNode.addChild(new TreeNode("insert"));
            if (SYM.getValue().equalsIgnoreCase("into")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    if (SYM.getValue().equalsIgnoreCase("values")) {
                        ADVANCE();
                        if (SYM.getValue().equalsIgnoreCase("(")) {
                            ADVANCE();
                            curNode.addChild(new TreeNode("valueList"));
                            curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                            VALUE_LIST();
                            if (flag) return;
                            if (SYM.getValue().equalsIgnoreCase(")")) {
                                ADVANCE();
                                END();
                                if (flag) return;
                                SUCCESS("insert");
                            } else ERROR("insert_S", ")");
                        } else ERROR("insert_S", "(");
                    } else ERROR("insert_S", "values");
                } else ERROR("insert_S", "TokenType.IDENTIFIER");
            } else ERROR("insert_S", "into");
        }
    }

    private void VALUE_LIST() {
        if (FIRST.VALUE_LIST.contains(SYM.getType().toString())) {
            VALUE();
            if (flag) return;
            if (SYM.getValue().equalsIgnoreCase(",")) {
                ADVANCE();
                VALUE_LIST();
            }
        } else {
            ERROR("VALUE_LIST", "FIRST.VALUE_LIST:" + FIRST.VALUE_LIST);
        }
    }

    private void VALUE() {
        if (FIRST.VALUE.contains(SYM.getType().toString())) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
        } else {
            ERROR("VALUE", "FIRST.VALUE:" + FIRST.VALUE);
        }
    }

    private void update_S() {
        if (SYM.getValue().equalsIgnoreCase("update")) {
            curNode.addChild(new TreeNode("update"));
            ADVANCE();
            if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                curNode.addChild(new TreeNode(SYM.getValue()));
                ADVANCE();
                if (SYM.getValue().equalsIgnoreCase("set")) {
                    curNode.addChild(new TreeNode("colUpdate"));
                    TreeNode saveNode = curNode;
                    curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                    ADVANCE();
                    COL_UPDATE_LIST();
                    if (flag) return;
                    curNode = saveNode;
                    curNode.addChild(new TreeNode("whereClause"));
                    curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                    WHERE_CLAUSE();
                    if (flag) return;
                    END();
                    if (flag) return;
                    SUCCESS("update");
                } else ERROR("update_S", "set");
            } else ERROR("update_S", "TokenType.IDENTIFIER");
        }
    }

    private void COL_UPDATE_LIST() {
        if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
            if (SYM.getValue().equalsIgnoreCase("=")) {
                ADVANCE();
                VALUE();
                if (flag) return;
                if (SYM.getValue().equalsIgnoreCase(",")) {
                    ADVANCE();
                    COL_UPDATE_LIST();
                }
            } else ERROR("COL_UPDATE_LIST", "=");
        } else ERROR("COL_UPDATE_LIST", "TokenType.IDENTIFIER");
    }

    private void WHERE_CLAUSE() {
        if (SYM.getValue().equalsIgnoreCase("where")) {
            ADVANCE();
            COL_SELECT_LIST();
        }
    }

    private void COL_SELECT_LIST() {
        if (FIRST.COL_SELECT_LIST.contains(SYM.getType().toString())) {
            CONDITION();
            if (flag) return;
            if (FIRST.LOGICAL_OPERATOR.contains(SYM.getValue())) {
                LOGICAL_OPERATOR();
                COL_SELECT_LIST();
            }
        }
    }

    private void CONDITION() {
        if(Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
            OPERATOR();
            if (flag) return;
            VALUE();
        }
    }

    private void OPERATOR() {
        if (FIRST.OPERATOR.contains(SYM.getValue())) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
        }
    }

    private void LOGICAL_OPERATOR() {
        if (SYM.getValue().equalsIgnoreCase(",")) {
            ADVANCE();
        }
    }

    private void delete_S() {
        if (SYM.getValue().equalsIgnoreCase("delete")) {
            curNode.addChild(new TreeNode("delete"));
            ADVANCE();
            if (SYM.getValue().equalsIgnoreCase("from")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    curNode.addChild(new TreeNode("whereClause"));
                    curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                    WHERE_CLAUSE();
                    END();
                    if (flag) return;
                    SUCCESS("delete");
                } else ERROR("delete_S", "TokenType.IDENTIFIER");
            } else ERROR("delete_S", "from");
        }
    }

    private void select_S() {
        if (SYM.getValue().equalsIgnoreCase("select")) {
            ADVANCE();
            curNode.addChild(new TreeNode("select"));
            curNode.addChild(new TreeNode("selectList"));
            TreeNode saveNode = curNode;
            curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
            SELECT_LIST();
            if (flag) return;
            if (SYM.getValue().equalsIgnoreCase("from")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode = saveNode;
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    curNode = saveNode;
                    curNode.addChild(new TreeNode("whereClause"));
                    curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                    WHERE_CLAUSE();
                    if(flag) return;
                    curNode = saveNode;
                    curNode.addChild(new TreeNode("orderByClause"));
                    curNode = curNode.getChildren().get(curNode.getChildren().size()-1);
                    ORDER_BY_CLAUSE();
                    if (flag) return;
                    END();
                    if (flag) return;
                    SUCCESS("select");
                } else ERROR("select_S", "TokenType.IDENTIFIER");
            } else ERROR("select_S", "from");
        }
    }

    private void SELECT_LIST() {
        if (FIRST.SELECT_LIST.contains(SYM.getType().toString()) || Objects.equals(SYM.getValue(), "*") || Objects.equals(SYM.getValue(), ",")) {
            if (SYM.getValue().equalsIgnoreCase("*")) {
                ADVANCE();
                curNode.addChild(new TreeNode("*"));
            } else if (Objects.equals(SYM.getValue(), ",")) {
                ADVANCE();
                SELECT_LIST();
            } else if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.OPERATOR)) {
                    pos -= 2;
                    ADVANCE();
                    COL_SELECT_LIST();
                } else {
                    pos -= 2;
                    ADVANCE();
                    COL_LIST();
                }
            } else ERROR("SELECT_LIST", "TokenType.IDENTIFIER");
        } else ERROR("SELECT_LIST", "FIRST.SELECT_LIST:" + FIRST.SELECT_LIST);
    }

    private void COL_LIST() {
        if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
            if (SYM.getValue().equalsIgnoreCase(",")) {
                ADVANCE();
                SELECT_LIST();
            }
        } else ERROR("COL_LIST", "FIRST.COL_LIST/FOLLOW.COL_LIST" + FIRST.COL_LIST + "/" + FOLLOW.COL_LIST);
    }

    private void ORDER_BY_CLAUSE() {
        if (SYM.getValue().equalsIgnoreCase("order")) {
            ADVANCE();
            if (SYM.getValue().equalsIgnoreCase("by")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    SORT();
                } else ERROR("ORDER_BY_CLAUSE", "TokenType.IDENTIFIER");
            } else ERROR("ORDER_BY_CLAUSE", "by");
        } else if (!FOLLOW.ORDER_BY_CLAUSE.contains(SYM.getValue())) {
            ERROR("ORDER_BY_CLAUSE", "order");
        }
    }

    private void SORT() {
        if (SYM.getValue().equalsIgnoreCase("desc")) {
            curNode.addChild(new TreeNode(SYM.getValue()));
            ADVANCE();
        } else {
            // 默认升序
            curNode.addChild(new TreeNode("asc"));
        }
    }

    private void desc_S() {
        if (SYM.getValue().equalsIgnoreCase("desc")) {
            curNode.addChild(new TreeNode("desc"));
            ADVANCE();
            if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                curNode.addChild(new TreeNode(SYM.getValue()));
                ADVANCE();
                END();
            } else ERROR("desc_S", "TokenType.IDENTIFIER");
        }
    }

    private void drop_S() {
        if (SYM.getValue().equalsIgnoreCase("drop")) {
            curNode.addChild(new TreeNode("drop"));
            ADVANCE();
            if (SYM.getValue().equalsIgnoreCase("table")) {
                ADVANCE();
                if (Objects.equals(SYM.getType(), TokenType.IDENTIFIER)) {
                    curNode.addChild(new TreeNode(SYM.getValue()));
                    ADVANCE();
                    END();
                }
            } else ERROR("desc_S", "table");
        }
    }




}
